/**
 * @file Rune.cpp
 * @author enemy1205 (enemy1205@qq.com)
 * @brief 能量机关类
 * @date 2021-08-16
 *
 */
#include "Rune.h"

using namespace cv;
using namespace std;

/**
 * @brief 神符装甲板构造函数
 * @param R_armor 旋转矩形
 */
Rune_Armor::Rune_Armor(RotatedRect &R_armor) {
    /*神符宽长于高*/
    this->width = max(R_armor.size.height, R_armor.size.width);
    this->height = min(R_armor.size.height, R_armor.size.width);
    this->angle = R_armor.angle;
    this->center = R_armor.center;
    R_armor.points(this->vertexes);
}

/**
 * @brief 过滤神符中心
 * @param temp 旋转矩形
 * @param contour 轮廓点集
 * @return 是否为神符中心
 */
bool Rune::Filter_center(RotatedRect &temp, const vector<Point> &contour) {
    double area = contourArea(contour);
//    cout<<area<<endl;
    if (area < R_param.R_minarea || area > R_param.R_maxarea) return false;
    else {
        temp = minAreaRect(contour);
        if (temp.size.height / temp.size.width < R_param.Max_Rune_center_ratio &&
            temp.size.height / temp.size.width > R_param.Min_Rune_center_ratio)
            return true;
        return false;
    }
}

/**
 * @brief 神符构造函数
 * @param contours 所有点集轮廓
 * @param hierarchy 轮廓关系
 */
Rune::Rune(const vector<vector<Point>> &contours, const vector<Vec4i> &hierarchy) {
    // init
    this->R_Armor = nullptr;
//    this->rotate_radius = 0.f;
    for (int i = 0; i < contours.size(); ++i) {
        /*无同级，无子级，仅父级，神符装甲板*/
        //        cout<<contours[i]<<endl;
        if (hierarchy[i][0] == -1 && hierarchy[i][1] == -1 && hierarchy[i][2] == -1 && hierarchy[i][3] != -1) {
            RotatedRect Fitting_rect = fitEllipse(contours[i]);
            //            cout<<Fitting_rect.size.height/Fitting_rect.size.width<<endl;
            R_Armor_ptr temp = make_shared<Rune_Armor>(Fitting_rect);
            if (temp->wh_ratio() > R_param.max_lw_ratio || temp->wh_ratio() < R_param.min_lw_ratio) continue;
            this->R_Armor = temp;
        }
        /*有同级，无父子级，神符中心*///取消同级轮廓限制有助于在仅有神符中心时识别到中心
        if (/*(hierarchy[i][0] != -1 || hierarchy[i][1] != -1) &&*/ hierarchy[i][2] == -1 && hierarchy[i][3] == -1) {
            RotatedRect temp;
            if (Filter_center(temp, contours[i])) this->center = temp.center;
        }
        /*有同级，有父无子级，已激活神符*/
//        if ((hierarchy[i][0] != -1 || hierarchy[i][1] != -1) && hierarchy[i][2] == -1 && hierarchy[i][3] != -1) {
//            RotatedRect Fitting_rect = fitEllipse(contours[i]);
//            R_Armor_ptr temp= make_shared<Rune_Armor>(Fitting_rect);
//            temp->validity = true;
//            this->R_Armor=temp;
//        }
    }
}

/**
 * @brief 获取神符旋转角度
 */
void Rune::calculateRotatedAngle() {
    float delta_x = this->R_Armor->getCenter().x - this->center.x;
    float delta_y = this->center.y - this->R_Armor->getCenter().y;
    // 范围 (-180, 180]
    if (delta_x == 0.f) {
        angle = (delta_y > 0) ? 90.f : -90.f;
    } else {
        angle = Rad2Deg(atanf(delta_y / delta_x));
        if (delta_x < 0.f) {
            angle = (angle > 0) ? angle - 180.f : angle + 180.f;//否则在delta_x < 0.f时angle为[-90,90].
        }
    }
}

/**
 * @brief 给神符装甲板角点排序
 */
void Rune::calculatePoints() {
    // -------------------------------【获取神符四个角点】-------------------------------
    // 四个角点
    Point2f four_corners[4];
    for (int i=0;i<4;i++) {
        four_corners[i]=this->R_Armor->getVertexes()[i];
    }
    // 按照离神符中心远近升序角点
    sort(begin(four_corners), end(four_corners),
         [&](const Point2f &p1, const Point2f &p2) -> bool {
             return getDistance(p1, this->center) < getDistance(p2, this->center);
         });
    // 存储靠近神符中心的角点
    Point2f bottom_1 = four_corners[0];
    Point2f bottom_2 = four_corners[1];
    // 存储远离神符中心的角点
    Point2f top_1 = four_corners[2];
    Point2f top_2 = four_corners[3];
    // ------------【判断角度大小来获取相对于神符装甲板中心左角点 or 右角点】------------
    // bottom_angle
    float bottom_delta_angle = getHorizontalAngle(bottom_1, this->center) -
                               getHorizontalAngle(bottom_2, this->center);
    // 得到 bottom_left / right
    if (bottom_delta_angle < -90.f) {
        bottom_delta_angle += 180.f;
    } else if (bottom_delta_angle > 90.f) {
        bottom_delta_angle -= 180.f;
    }
    this->R_Armor->getVertexes()[0]= (bottom_delta_angle > 0.f) ? bottom_1 : bottom_2;//bottom_left
    this->R_Armor->getVertexes()[3]= (bottom_delta_angle < 0.f) ? bottom_1 : bottom_2;//bottom_right
    // top_angle
    float top_delta_angle = getHorizontalAngle(top_1, this->center) -
                            getHorizontalAngle(top_2, this->center);
    // 得到 top_left / right
    if (top_delta_angle < -90.f) {
        top_delta_angle += 180.f;
    } else if (top_delta_angle > 90.f) {
        top_delta_angle -= 180.f;
    }
    this->R_Armor->getVertexes()[1]= (top_delta_angle > 0.f) ? top_1 : top_2;//top_left
    this->R_Armor->getVertexes()[2]= (top_delta_angle < 0.f) ? top_1 : top_2;//top_right
}

/**
 * @brief 确认为神符后再进行的运算，减少运算量
 */
void Rune::updateRestInfo() {
    if (this->R_Armor != nullptr && center != Point2f(0, 0)) {
        this->calculateRotatedAngle();
        this->calculatePoints();
        this->validity= true;
    } else this->validity= false;
}